package com.zjtx.tech.demo.service;

import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.Metrics;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class RedisGeoService {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 向指定的Geo集合中添加成员，附带其地理坐标
     *
     * @param key       Geo集合的键，标识一个Geo集合
     * @param member    需要添加的成员
     * @param longitude 经度，表示成员的地理坐标位置
     * @param latitude  纬度，表示成员的地理坐标位置
     */
    public void addMember(String key, String member, double longitude, double latitude) {
        redisTemplate.opsForGeo().add(key, new Point(longitude, latitude), member);
    }

    /**
     * 根据指定的圆范围查询Geo集合中的成员
     * 此方法用于查询给定Geo集合中，在指定圆范围内的所有成员，圆的中心由经纬度指定，半径为5公里
     *
     * @param key       Geo集合的键，标识一个Geo集合
     * @param longitude 圆心的经度
     * @param latitude  圆心的纬度
     */
    public void radius(String key, double longitude, double latitude, int radius) {
        Point center = new Point(longitude, latitude);
        Circle circle = new Circle(center, new Distance(radius, Metrics.KILOMETERS));
        redisTemplate.opsForGeo().radius(key, circle);
    }

    /**
     * 根据指定的圆范围查询Geo集合中的成员，并按距离排序
     * <p>
     * 此方法用于查询给定Geo集合中，在指定圆范围内的所有成员，圆的中心由经纬度指定，半径为5公里。
     * 查询结果将按照距离从近到远排序
     *
     * @param key       Geo集合的键，标识一个Geo集合
     * @param longitude 圆心的经度
     * @param latitude  圆心的纬度
     * @return 按距离排序的查询结果
     */
    public GeoResults<RedisGeoCommands.GeoLocation<String>> radiusCondition(String key, double longitude, double latitude, int radius, long count) {
        Point center = new Point(longitude, latitude);
        Circle circle = new Circle(center, new Distance(radius, Metrics.KILOMETERS));
        RedisGeoCommands.GeoRadiusCommandArgs args =
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                        .includeDistance().includeCoordinates().sortAscending().limit(count);
        return redisTemplate.opsForGeo().radius(key, circle, args);
    }

}
